﻿using Cinch;
using System;
using System.ComponentModel;
using System.Deployment.Application;

namespace FR.SAFTAnalyser.Services
{
    public class SoftwareUpdate
    {
        //the update is available to download
        bool isUpdateAvailable;
        public bool IsUpdateAvailable
        {
            get { return isUpdateAvailable; }
            set
            {
                isUpdateAvailable = value;
                Mediator.Instance.NotifyColleaguesAsync<bool>(MessageType.UPDATE_AVAILABLE, isUpdateAvailable);
            }
        }

        //the update has been downloaded ans its ready to install
        bool isUpdateReady;
        public bool IsUpdateReady
        {
            get { return isUpdateReady; }
            set
            {
                isUpdateReady = value;
                Mediator.Instance.NotifyColleaguesAsync<bool>(MessageType.UPDATE_READY, isUpdateReady);
            }
        }

        string updateStatus;
        public string UpdateStatus
        {
            get { return updateStatus; }
            set
            {
                updateStatus = value;

                Mediator.Instance.NotifyColleaguesAsync<string>(MessageType.UPDATE_STATUS, updateStatus);
            }
        }

        ApplicationDeployment ad;
        public void FindUpdates()
        {
            //procurar updates async
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                ad = ApplicationDeployment.CurrentDeployment;

                //eventos de update
                ad.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);
                ad.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(ad_CheckForUpdateProgressChanged);

                ad.CheckForUpdateAsync();
            }
        }

        private void ad_CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            UpdateStatus = string.Format("Downloading: {0}. {1:D}K de {2:D}K downloaded.", GetProgressString(e.State), e.BytesCompleted / 1024, e.BytesTotal / 1024);
        }

        private string GetProgressString(DeploymentProgressState state)
        {
            if (state == DeploymentProgressState.DownloadingApplicationFiles)
            {
                return "application files";
            }
            else if (state == DeploymentProgressState.DownloadingApplicationInformation)
            {
                return "application manifest";
            }
            else
            {
                return "deployment manifest";
            }
        }

        private void ad_CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                UpdateStatus = string.Format(
                    "ERRO: Não foi possível obter uma actualização da aplicação. Razão: {1}{0}", e.Error.Message, Environment.NewLine);
                return;
            }
            else if (e.Cancelled == true)
                UpdateStatus = "O update foi cancelado.";

            // Ask the user if they would like to update the application now.
            if (e.UpdateAvailable)
            {
                IsUpdateAvailable = true;

                UpdateStatus = string.Format(
                    "Está disponível a versão{0}.{2}Quer actualizar a aplicação agora?{2}{2}Download bytes: {1}", e.AvailableVersion, e.UpdateSizeBytes, Environment.NewLine);
            }
            else
            {
                IsUpdateAvailable = false;
                UpdateStatus = "Versão está actualizada.";
            }

            ad.CheckForUpdateCompleted -= new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);
            ad.CheckForUpdateProgressChanged -= new DeploymentProgressChangedEventHandler(ad_CheckForUpdateProgressChanged);
        }

        public void BeginUpdate()
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
                ad.UpdateCompleted += new AsyncCompletedEventHandler(ad_UpdateCompleted);

                // Indicate progress in the application's status bar.
                ad.UpdateProgressChanged += new DeploymentProgressChangedEventHandler(ad_UpdateProgressChanged);
                ad.UpdateAsync();
            }
            else
                UpdateStatus = "Offline";
        }

        private void ad_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            UpdateStatus = string.Format("{0:D}K de {1:D}K downloaded - {2:D}% completo", e.BytesCompleted / 1024, e.BytesTotal / 1024, e.ProgressPercentage);
        }

        private void ad_UpdateCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                UpdateStatus = "O update da aplicação foi cancelado.";
                return;
            }
            else if (e.Error != null)
            {
                UpdateStatus = string.Format(
                    "ERRO: Não foi possível instalar o update da aplicação. Razão: {1}{0}", e.Error.Message, Environment.NewLine);
                return;
            }

            IsUpdateReady = true;
            //update concluido, tudo ok
            UpdateStatus = string.Format(
                "A aplicação foi actualizada. Reiniciar a aplicação para aplicar as alterações.{0}Se não for reiniciada agora, a nova versão só terá efeito quando a aplicação for fechada e iniciada novamente.", Environment.NewLine);
        }

        public void RestartApp()
        {
            System.Diagnostics.Process.Start(System.Windows.Application.ResourceAssembly.Location);
            System.Windows.Application.Current.Shutdown();
        }
    }
}
